/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.controller.admin;

import cn.easyplatform.messages.request.SimpleRequestMessage;
import cn.easyplatform.messages.request.admin.ServiceRequestMessage;
import cn.easyplatform.messages.vos.admin.ServiceVo;
import cn.easyplatform.spi.service.AdminService;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.type.ServiceType;
import cn.easyplatform.type.StateType;
import cn.easyplatform.web.contexts.Contexts;
import cn.easyplatform.web.dialog.MessageBox;
import cn.easyplatform.web.listener.MessageEventListener;
import cn.easyplatform.web.log.LogManager;
import cn.easyplatform.web.message.entity.Message;
import cn.easyplatform.web.service.ServiceLocator;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.CheckEvent;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.*;

import java.util.Date;
import java.util.List;
import java.util.Map;


/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class ServiceController extends SelectorComposer<Component> {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    @Wire("button#serviceOp")
    private Button serviceOp;

    @Wire("label#startTime")
    private Label startTime;

    @Wire("listbox#services")
    private Listbox services;

    @Wire("textbox#rt")
    private Textbox rt;

    @Wire("combobox#level")
    private Combobox level;

    @Wire("html#console")
    private Html console;

    private EventListener<Event> consoleSubscriber;

    @Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
        level.setSelectedIndex(2);
        AdminService as = ServiceLocator.lookup(AdminService.class);
        IResponseMessage<?> resp = as.getServices(new SimpleRequestMessage(ServiceType.CUSTOM_SERVICE));
        if (resp.isSuccess()) {
            List<ServiceVo> ss = (List<ServiceVo>) resp.getBody();
            for (ServiceVo s : ss) {
                Listitem item = new Listitem();
                item.appendChild(new Listcell(s.getId()));
                item.appendChild(new Listcell(s.getName()));
                if (s.getState() == StateType.STOP) {
                    item.appendChild(new Listcell(Labels.getLabel("admin.service.state.normal")));
                } else {
                    item.appendChild(new Listcell(Labels.getLabel("admin.service.state.blocked")));
                }
                item.setValue(s);
                services.appendChild(item);
            }
            final EventListener el = event -> {
                if (services.getSelectedItem() == null)
                    return;
                ServiceVo vo = services.getSelectedItem().getValue();
                if (consoleSubscriber != null) {
                    ServiceLocator.lookup(AdminService.class).console(new SimpleRequestMessage(new Object[]{"sys." + vo.getId(), false}));
                    Contexts.unsubscribe(Message.LOG, consoleSubscriber);
                    consoleSubscriber = null;
                }
            };
            Tabpanel c = (Tabpanel) comp.getParent().getParent();
            c.getLinkedTab().addEventListener(Events.ON_CLOSE, el);
            if (!ss.isEmpty()) {
                services.setSelectedIndex(0);
                onSelect();
            }
        } else {
            MessageBox.showMessage(resp);
            comp.detach();
        }
    }

    @Listen("onSelect=#services")
    public void onSelect() {
        ServiceVo vo = services.getSelectedItem().getValue();
        setState(vo);
    }

    @Listen("onSelect = #level")
    public void onSetLevel() {
        if (services.getSelectedItem() == null)
            return;
        if (consoleSubscriber == null) {
            MessageBox.showMessage(Labels.getLabel("message.dialog.title.info"), Labels.getLabel("admin.log.set.level"));
        } else {
            console.setContent("$$clear$$");
            ServiceVo vo = services.getSelectedItem().getValue();
            ServiceLocator.lookup(AdminService.class).console(new SimpleRequestMessage(new Object[]{"sys." + vo.getId(), level.getSelectedItem().getLabel()}));
        }
    }

    @Listen("onCheck = #switchLog")
    public void onSwitchLog(CheckEvent evt) {
        if (services.getSelectedItem() == null)
            return;
        ServiceVo vo = services.getSelectedItem().getValue();
        IResponseMessage<?> resp = ServiceLocator.lookup(AdminService.class).console(new SimpleRequestMessage(new Object[]{"sys." + vo.getId(), evt.isChecked()}));
        if (resp.isSuccess()) {
            if (evt.isChecked()) {
                consoleSubscriber = new MessageEventListener(console);
                Contexts.subscribe(Message.LOG, consoleSubscriber);
            } else {
                Contexts.unsubscribe(Message.LOG, consoleSubscriber);
                consoleSubscriber = null;
            }
        } else
            MessageBox.showMessage(resp);
    }

    private void setState(ServiceVo vo) {
        serviceOp.setDisabled(false);
        if (vo.getState() == StateType.STOP) {
            serviceOp.setLabel(Labels.getLabel("admin.service.start"));
            serviceOp.setIconSclass("z-icon-play");
        } else if (vo.getState() == StateType.START) {
            serviceOp.setLabel(Labels.getLabel("admin.service.stop"));
            serviceOp.setIconSclass("z-icon-cog z-icon-spin");
        }
        Date date = vo.getAsDate("service.start.time");
        if (date != null) {
            startTime.setValue(DateFormatUtils.format(date,
                    "yyyy-MM-dd hh:mm:ss"));
        } else
            startTime.setValue(null);
        if (vo.getKeySet() != null) {
            StringBuilder sb = new StringBuilder();
            for (String name : vo.getKeySet()) {
                if (!name.equals("service.start.time"))
                    sb.append(name).append(":").append(vo.getValue(name)).append("\n");
            }
            rt.setValue(sb.toString());
        } else
            rt.setValue("");
    }

    @Listen("onClick=#serviceOp")
    public void onOp() {
        String msg = null;
        final ServiceVo vo = services.getSelectedItem().getValue();
        int s = vo.getState();
        if (s == StateType.START) {
            msg = Labels.getLabel("admin.service.stop");
            s = StateType.STOP;
        } else {
            msg = Labels.getLabel("admin.service.start");
            s = StateType.START;
        }
        final int state = s;
        Messagebox.show(Labels.getLabel("admin.service.op.confirm",
                new Object[]{msg}), Labels
                        .getLabel("admin.service.op.title"), Messagebox.CANCEL
                        | Messagebox.OK, Messagebox.QUESTION,
                evt -> {
                    if (evt.getName().equals(Messagebox.ON_OK)) {
                        AdminService as = ServiceLocator
                                .lookup(AdminService.class);
                        IResponseMessage<?> resp = as
                                .setServiceState(new ServiceRequestMessage(
                                        new ServiceVo(vo.getId(), ServiceType.CUSTOM_SERVICE, state)));
                        if (resp.isSuccess()) {
                            vo.setState(state);
                            vo.setRuntimeInfo((Map<String, Object>) resp.getBody());
                            Listcell lc = (Listcell) services.getSelectedItem().getLastChild();
                            if (vo.getState() == StateType.STOP) {
                                lc.setLabel(Labels.getLabel("admin.service.state.normal"));
                            } else if (vo.getState() == StateType.START) {
                                lc.setLabel(Labels.getLabel("admin.service.state.blocked"));
                            }
                            setState(vo);
                        } else {
                            MessageBox.showMessage(resp);
                        }
                    }
                });
    }

}
